//
//  WXApiTool.m
//  DaJiang
//
//  Created by sally on 16/10/10.
//  Copyright © 2016年 jiniu. All rights reserved.
// 资料参考:https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=9_1
// 资料参考:https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=8_5

#import "ApiXml.h"
#import "WXApiTool.h"
#import "WXUtil.h"

@implementation WXApiTool
singleton_implementation(WXApiTool)

#pragma mark 检查是否安装了微信
- (BOOL) checkHasInstall {
  if ([WXApi isWXAppInstalled] == NO) {
    return NO;
  } else {
    return YES;
  }
}

#pragma mark 调起微信支付
- (void)WXPayWithOrderName:(NSString *)name orderNum:(NSString *)orderNum price:(NSString *)price {
  self.notifyURL = @"https://pay.weixin.qq.com/wxpay/pay.action";
  NSMutableDictionary *dict = [self getPrepayWithOrderName:name orderNum:orderNum price:price device:@"WEB" notifyURL:self.notifyURL];

  PayReq *req = [[PayReq alloc] init];
  req.openID = [dict objectForKey:@"appid"];
  req.partnerId = [dict objectForKey:@"partnerid"];
  req.prepayId = [dict objectForKey:@"prepayid"];
  req.nonceStr = [dict objectForKey:@"noncestr"];
  req.timeStamp = [[dict objectForKey:@"timestamp"] intValue];
  req.package = [dict objectForKey:@"package"];
  req.sign = [dict objectForKey:@"sign"];

  [WXApi sendReq:req];
}

#pragma mark 支付后回调
- (void)onResp:(BaseResp *)resp {
  if ([resp isKindOfClass:[PayResp class]]) {
    PayResp *response = (PayResp *) resp;
    switch (response.errCode) {
      case WXSuccess:
        //服务器端查询支付通知或查询API返回的结果再提示成功
        NSLog(@"支付成功");
        if (self.delegate && [self.delegate respondsToSelector:@selector(noticeWXPaySuccess)]) {
          [self.delegate noticeWXPaySuccess];
        }
        break;
      default:
        NSLog(@"支付失败，retcode=%d", resp.errCode);
        break;
    }
  }
}

#pragma mark 获取预支付订单信息（核心是一个prepayID）
- (NSMutableDictionary *)getPrepayWithOrderName:(NSString *)name orderNum:(NSString *)orderNum price:(NSString *)price device:(NSString *)device notifyURL:(NSString *)notifyURL {

  //订单标题，展示给用户
  NSString *orderName = name;
  //订单号，传给后台；
  NSString *orderNumber = orderNum;
  //支付通知的回调地址
  NSString *notifyUrl = notifyURL;
  //订单金额,单位（分）
  NSString *orderPrice = price; //以分为单位的整数
  //支付设备号或门店号
  NSString *orderDevice = device;
  //支付类型，固定为APP
  NSString *orderType = @"APP";
  //发器支付的机器ip,暂时没有发现其作用
  NSString *orderIP = @"196.168.1.1";

  //随机数串
  srand((unsigned) time(0));
  NSString *noncestr = [NSString stringWithFormat:@"%d", rand()];
  NSString *orderNO = [NSString stringWithFormat:@"%ld", time(0)];

  //================================
  //预付单参数订单设置
  //================================
  NSMutableDictionary *packageParams = [NSMutableDictionary dictionary];

  self.payURL = @"https://api.mch.weixin.qq.com/pay/unifiedorder";
  if (self.debugInfo == nil) {
    self.debugInfo = [NSMutableString string];
  }
  [self.debugInfo setString:@""];
  self.appID = WXAppKey;    //微信分配给商户的appID
  self.mchID = WXMchID;     //
  self.spKey = WXPartnerID; //商户的密钥

  [packageParams setObject:self.appID forKey:@"appid"];         //开放平台appid
  [packageParams setObject:self.mchID forKey:@"mch_id"];        //商户号
  [packageParams setObject:orderDevice forKey:@"device_info"];  //支付设备号或门店号
  [packageParams setObject:noncestr forKey:@"nonce_str"];       //随机串
  [packageParams setObject:orderName forKey:@"body"];           //订单描述，展示给用户
  [packageParams setObject:orderNumber forKey:@"attach"];       //附加数据-订单号
  [packageParams setObject:orderNO forKey:@"out_trade_no"];     //商户订单号
  [packageParams setObject:orderPrice forKey:@"total_fee"];     //订单金额，单位为分
  [packageParams setObject:orderIP forKey:@"spbill_create_ip"]; //发器支付的机器ip
  [packageParams setObject:notifyUrl forKey:@"notify_url"];     //支付结果异步通知
  [packageParams setObject:orderType forKey:@"trade_type"];     //支付类型，固定为APP

  //=================下预付单-获取prepayId（预支付交易会话标识）=================
  NSString *prePayid;
  prePayid = [self sendPrepay:packageParams];

  if (prePayid == nil) {
    [self.debugInfo appendFormat:@"获取prepayid失败！\n"];
    return nil;
  }

  //获取到prepayid后进行第二次签名
  NSString *package, *time_stamp, *nonce_str;
  //设置支付参数
  time_t now;
  time(&now);
  time_stamp = [NSString stringWithFormat:@"%ld", now];
  nonce_str = [WXUtil md5:time_stamp];
  //重新按提交格式组包，微信客户端暂只支持package=Sign=WXPay格式，须考虑升级后支持携带package具体参数的情况
  //package = [NSString stringWithFormat:@"Sign=%@",package];
  package = @"Sign=WXPay";
  //=================第二次签名参数列表===================
  NSMutableDictionary *signParams = [NSMutableDictionary dictionary];
  [signParams setObject:self.appID forKey:@"appid"];
  [signParams setObject:self.mchID forKey:@"partnerid"];
  [signParams setObject:prePayid forKey:@"prepayid"];
  [signParams setObject:package forKey:@"package"];
  [signParams setObject:nonce_str forKey:@"noncestr"];
  [signParams setObject:time_stamp forKey:@"timestamp"];

  //生成签名
  NSString *sign = [self createMd5Sign:signParams];
  //添加签名
  [signParams setObject:sign forKey:@"sign"];

  [self.debugInfo appendFormat:@"第二步签名成功，sign＝%@\n", sign];

  //返回参数列表
  return signParams;
}

#pragma mark 提交预支付
- (NSString *)sendPrepay:(NSMutableDictionary *)prePayParams {
  NSString *prepayid = nil;

  //获取提交支付
  NSString *send = [self genPackage:prePayParams];
  //输出Debug Info
  [self.debugInfo appendFormat:@"API链接:%@\n", self.payURL];
  [self.debugInfo appendFormat:@"发送的xml:%@\n", send];

  //发送请求post xml数据
  NSData *res = [WXUtil httpSend:self.payURL method:@"POST" data:send];

  //输出Debug Info
  [self.debugInfo appendFormat:@"服务器返回：\n%@\n\n", [[NSString alloc] initWithData:res encoding:NSUTF8StringEncoding]];

  XMLHelper *xml = [[XMLHelper alloc] init];

  //开始解析
  [xml startParse:res];

  NSMutableDictionary *resParams = [xml getDict];
  NSLog(@"%@", resParams);

  //判断返回
  NSString *return_code = [resParams objectForKey:@"return_code"];
  NSLog(@"%@", return_code);

  NSString *result_code = [resParams objectForKey:@"result_code"];
  NSLog(@"%@", result_code);

  if ([return_code isEqualToString:@"SUCCESS"]) {
    //生成返回数据的签名
    NSString *sign = [self createMd5Sign:resParams];
    NSString *send_sign = [resParams objectForKey:@"sign"];

    //验证签名正确性
    if ([sign isEqualToString:send_sign]) {
      if ([result_code isEqualToString:@"SUCCESS"]) {
        //验证业务处理状态
        prepayid = [resParams objectForKey:@"prepay_id"];
        return_code = 0;

        [self.debugInfo appendFormat:@"获取预支付交易标示成功！\n"];
      }
    } else {
      self.lastErrCode = 1;
      [self.debugInfo appendFormat:@"gen_sign=%@\n   _sign=%@\n", sign, send_sign];
      [self.debugInfo appendFormat:@"服务器返回签名验证错误！！！\n"];
    }
  } else {
    self.lastErrCode = 2;
    [self.debugInfo appendFormat:@"接口返回错误！！！\n"];
  }

  return prepayid;
}

#pragma mark 获取package带参数的签名包
- (NSString *)genPackage:(NSMutableDictionary *)packageParams {
  //NSLog(@"%@",packageParams);

  NSString *sign;
  NSMutableString *reqPars = [NSMutableString string];
  //生成签名
  sign = [self createMd5Sign:packageParams];
  //生成xml的package
  NSArray *keys = [packageParams allKeys];
  [reqPars appendString:@"<xml>\n"];
  for (NSString *categoryId in keys) {
    [reqPars appendFormat:@"<%@>%@</%@>\n", categoryId, [packageParams objectForKey:categoryId], categoryId];
  }
  [reqPars appendFormat:@"<sign>%@</sign>\n</xml>", sign];

  return [NSString stringWithString:reqPars];
}

#pragma mark 创建package签名
- (NSString *)createMd5Sign:(NSMutableDictionary *)dict {
  NSMutableString *contentString = [NSMutableString string];
  NSArray *keys = [dict allKeys];
  //NSLog(@"dict:%@", dict);

  //按字母顺序排序
  NSArray *sortedArray = [keys sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2) {
    return [obj1 compare:obj2 options:NSNumericSearch];
  }];
  //NSLog(@"sortedArray:%@", sortedArray);

  //拼接字符串
  for (NSString *categoryId in sortedArray) {
    if (![[dict objectForKey:categoryId] isEqualToString:@""] && ![categoryId isEqualToString:@"sign"] && ![categoryId isEqualToString:@"key"]) {
      [contentString appendFormat:@"%@=%@&", categoryId, [dict objectForKey:categoryId]];
    }
  }
  //NSLog(@"contentString:%@", contentString);

  //添加key字段
  [contentString appendFormat:@"key=%@", self.spKey];
  //得到MD5 sign签名
  NSString *md5Sign = [WXUtil md5:contentString];
  //NSLog(@"md5Sign:%@", md5Sign);

  //输出Debug Info
  [self.debugInfo appendFormat:@"MD5签名字符串：\n%@\n\n", contentString];

  return md5Sign;
}

#pragma mark 获取当前的debug信息
- (NSString *)getDebugInfo {
  NSString *res = [NSString stringWithString:self.debugInfo];
  [self.debugInfo setString:@""];
  return res;
}

@end
